package se392.ateam2006.resourcemgmt.participant.exclusionset;

import java.io.Serializable;
import java.util.Calendar;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Transient;
import java.util.Arrays;

import se392.ateam2006.resourcemgmt.participant.ParticipationEntity;
import se392.ateam2006.user.UserEntity;
import se392.ateam2006.meetingmgmt.meeting.MeetingEntity;

/**
 * Entity class to define the attributes and operations of an exclusion range (or a preference range)
 * This defines when a user can or cannot attend a meeting
 * A range is either an exclusion or a preference depending on the state of the 'preferenceSet' flag
 *      which seems REALLY safe... But this code has just been ported, as required, not improved.
 *      For future groups working on this code (chin up), a better way of implementing this would be to have
 *      a base class DateRange, and then derive two classes - ExclusionDateRange and PreferenceDateRange from it.
 * This information can then be persisted into a database
 * @author Ateam (Matthew Bennett, Claire Melton, Shingai Manyiwa, John Adderley)
 * @version 25/03/07
 */
@Entity
public class ExclusionRangeEntity implements Serializable{
    
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    
    @OneToOne
    private UserEntity userEnt;
    @OneToOne
    private MeetingEntity meetingEnt;
    @Temporal(TemporalType.DATE)
    private Calendar startDate;
    @Temporal(TemporalType.DATE)
    private Calendar endDate;
    private boolean preferenceSet;
    
    /**
     * Default constructor required as this is an entity class
     */
    public ExclusionRangeEntity() {}
    
    /**
     * Creates a new instance of ExclusionRangeEntity
     * @param ue - the UserEntity who owns the exclusion set
     * @param startDate - a Calendar defining the start of the exclusion/preference
     * @param endDate - a Calendar defining the end of the exclusion/preference
     * @param preferenceSet - boolean. Is this a preference or an exclusion range?
     */
    public ExclusionRangeEntity(UserEntity ue, Calendar startDate, 
                           Calendar endDate, boolean preferenceSet) {
        
        this(ue, null, startDate, endDate, preferenceSet);
    }
    
    /**
     * Creates a new instance of ExclusionRangeEntity
     * @param ue - the UserEntity who owns the exclusion set
     * @param me - the MeetingEntity that this is an exclusion/preference range for
     * @param startDate - a Calendar defining the start of the exclusion/preference
     * @param endDate - a Calendar defining the end of the exclusion/preference
     * @param preferenceSet - boolean. Is this a preference or an exclusion range?
     */
    public ExclusionRangeEntity(UserEntity ue, MeetingEntity me, Calendar startDate, 
                           Calendar endDate, boolean preferenceSet) {
        
        this.setUserEnt(ue);
        this.meetingEnt = me;
        this.startDate = startDate;
        this.endDate = endDate;
        this.preferenceSet = preferenceSet;
    }

    /**
     * Convert the object to an int array
     * This method is used by the MeetingTimeResolutionUtility to
     *      resolve meeting times for a set of ExclusionRangeEntity's
     * @param set - the ExclusionRangeEntity to be converted
     * @return int[] - array ov int representing the ExclusionRangeEntity
     *
     * The output array will contain a mixture of the following values:
     *
     *      -1 = exclusion. The user cannot make this time
     *       0 = No preference/exclusion. Assume the user can make this time
     *       1 = preference. The user would like the meeting to be at this time
     */
    protected int[] toIntArray() {
        
        // We're going to be dealing with 10 minute blocks of time as our native resolution
        // So we need an array to hold the number of 10 minute chunks in a day (i.e. 144)
        int[] out = new int[MeetingTimeResolutionUtility.SET_SIZE];
        // Temporary variables to store the start and end times
        int start, end;
        
        // Set all values to 0, which will be our default value
        Arrays.fill(out, 0);
        
        // Convert the start and end times (Calendars) into ints representing an index in the array
        start = (int)Math.floor(getStartTimeInMins() / 10);
        end   = (int)Math.ceil(getEndTimeInMins() / 10);
        
        // Now fill in the appropriate values in the array depending on if this is a preference or an exclusion set
        for(int i=start; i<end; i++) {
            
            // Yeah, yeah, yeah, this checks the value of the preferenceSet flag each time... Could be probably better, I know!
            out[i] = preferenceSet ? 1 : -1;
        }
        
        // All done, return the int array
        return out;
    }
    
    /**
     * Return the start time in minutes (counted from midnight)
     * This is used by the MeetingTimeResolutionUtility
     * @return int - the start time in minutes
     */
    protected int getStartTimeInMins() {
        
        // Logically we'll want to round this value down to the nearest minute
        return (int)Math.floor((startDate.get(Calendar.HOUR_OF_DAY) * 60) + (startDate.get(Calendar.MINUTE)));
    }
    
    /**
     * Return the end time in minutes (counted from midnight)
     * This is used by the MeetingTimeResolutionUtility
     * @return int - the end time in minutes
     */
    protected int getEndTimeInMins() {
        
        // Logically we'll want to round ths value up to the nearest minute
        return (int)Math.ceil((endDate.get(Calendar.HOUR_OF_DAY) * 60) + (endDate.get(Calendar.MINUTE)));
    }
    
    /**
     * Get the user entity who owns this exclusion range
     * @return UserEntity - the owning user
     */
    public UserEntity getUser() {
        return getUserEnt();
    }

    /**
     * Set the user entity who owns this exclusion range
     * @param ue - the new owning UserEntity
     */
    public void setUser(UserEntity ue) {
        this.setUserEnt(ue);
    }

    /**
     * Get the meeting entity that this exclusion range is for
     * @return MeetingEntity - the exclusion range's meeting
     */
    public MeetingEntity getMeeting() {
        return meetingEnt;
    }

    /**
     * Set the meeting entity that this exclusion range is for
     * @param me - the new meeting that the exclusion range is for
     */
    public void setMeeting(MeetingEntity me) {
        this.meetingEnt = me;
    }

    /**
     * Get the start date/time of the exclusion range
     * @return Calendar - the start date/time
     */
    public Calendar getStartDate() {
        return startDate;
    }

    /**
     * Set the start date/time of the exclusion range
     * @param startDate - the new start date/time
     */
    public void setStartDate(Calendar startDate) {
        this.startDate = startDate;
    }

    /**
     * Get the end date/time of the exclusion range
     * @return Calendar - the end date/time
     */
    public Calendar getEndDate() {
        return endDate;
    }

    /**
     * Set the end date/time of the exclusion range
     * @param endDate - the new end date/time
     */
    public void setEndDate(Calendar endDate) {
        this.endDate = endDate;
    }
    
    /**
     * Override the equals method...
     * @param obj - the object to compare to
     * @return boolean - are the objects equal?
     */
    public boolean equals(Object obj){
        
        if(obj ==null) return false;
        
        if(obj instanceof ExclusionRangeEntity) {
            
            ExclusionRangeEntity temp = (ExclusionRangeEntity)(obj);
            
            if((this.getUserEnt().equals(temp.getUserEnt())) &&
               (this.startDate.equals(temp.startDate)) &&
               (this.endDate.equals(temp.endDate)) &&
               (this.preferenceSet == temp.preferenceSet)) {
                
               if(this.meetingEnt != null && this.meetingEnt.equals(temp.meetingEnt)) {
                    return true;
               }
               
               if(this.meetingEnt == null && temp.meetingEnt == null) {
                   return true;
               }
            }
        }
        
        return false;
    }

    /**
     * Get whether this is a preference set
     * @return boolean - is this a preference set?
     */
    public boolean isPreferenceSet() {
        return preferenceSet;
    }
    
    /**
     * Get whether this is a preference set
     * @return boolean - is this a preference set?
     */
    public boolean getPreferenceSet() {
        return preferenceSet;
    }

    /**
     * Set whether this is a preference set
     * @param preferenceSet - the new state of the preferenceSet flag
     */
    public void setPreferenceSet(boolean preferenceSet) {
        this.preferenceSet = preferenceSet;
    }

    /**
     * Get the ID of this exclusion range
     * @return long - the exclusion range ID
     */
    public long getId() {
        return id;
    }

    /**
     * Set the ID of this exclusion range
     * @param id - the the ID
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * Get the user entity who owns this exclusion range
     * @return UserEntity - the owning user
     */
    public UserEntity getUserEnt() {
        return userEnt;
    }

    /**
     * Set the user entity who owns this exclusion range
     * @param ue - the new owning UserEntity
     */
    public void setUserEnt(UserEntity userEnt) {
        this.userEnt = userEnt;
    }
}
